package cn.tedu.tmall.passport.service.impl;

import cn.tedu.tmall.common.enumerator.ServiceCode;
import cn.tedu.tmall.common.ex.ServiceException;
import cn.tedu.tmall.common.pojo.authentication.CurrentPrincipal;
import cn.tedu.tmall.common.pojo.po.UserCachePO;
import cn.tedu.tmall.common.util.JwtUtils;
import cn.tedu.tmall.passport.dao.cache.IUserCacheRepository;
import cn.tedu.tmall.passport.dao.persist.repository.ILoginLogRepository;
import cn.tedu.tmall.passport.dao.persist.repository.IUserRepository;
import cn.tedu.tmall.passport.pojo.entity.LoginLog;
import cn.tedu.tmall.passport.pojo.param.UserLoginInfoParam;
import cn.tedu.tmall.passport.pojo.vo.UserLoginInfoVO;
import cn.tedu.tmall.passport.pojo.vo.UserLoginResultVO;
import cn.tedu.tmall.passport.service.IUserService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 处理用户数据的业务实现类
 *
 * @author java@tedu.cn
 * @version 3.0
 */
@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    @Value("${tmall.jwt.secret-key}")
    private String secretKey;
    @Autowired
    private IUserRepository userRepository;
    @Autowired
    private ILoginLogRepository loginLogRepository;
    @Autowired
    private IUserCacheRepository userCacheRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;

    public UserServiceImpl() {
        log.debug("创建业务类对象：UserServiceImpl");
    }

    @Override
    public UserLoginResultVO login(UserLoginInfoParam userLoginInfoParam,
                                   String remoteAddr, String userAgent) {
        log.debug("开始处理【用户登录】的业务，参数：{}", userLoginInfoParam);
        String username = userLoginInfoParam.getUsername();
        UserLoginInfoVO loginInfo = userRepository.getLoginInfoByUsername(username);
        if (loginInfo == null) {
            String message = "登录失败，用户名或密码错误！（开发阶段专用：用户名错误）";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }

        if (!loginInfo.getEnable().equals(ENABLE_STATE_ON)) {
            String message = "登录失败，此账号已经被禁用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED_DISABLED, message);
        }

        String password = userLoginInfoParam.getPassword();
        if (!passwordEncoder.matches(password, loginInfo.getPassword())) {
            String message = "登录失败，用户名或密码错误！（开发阶段专用：密码错误）";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }

        Long userId = loginInfo.getId();
        Integer loginCount = loginInfo.getLoginCount();
        String avatar = loginInfo.getAvatar();

        List<GrantedAuthority> authorities = new ArrayList<>();
        List<String> permissions = loginInfo.getPermissions();
        for (String permission : permissions) {
            authorities.add(new SimpleGrantedAuthority(permission));
        }
        String authoritiesJsonString = JSON.toJSONString(authorities);

        LocalDateTime now = LocalDateTime.now();
        LoginLog loginLog = new LoginLog();
        loginLog.setUserId(userId);
        loginLog.setUsername(username);
        loginLog.setIp(remoteAddr);
        loginLog.setUserAgent(userAgent);
        loginLog.setGmtLogin(now);
        int rows = loginLogRepository.insert(loginLog);
        if (rows != 1) {
            String message = "登录失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT, message);
        }

        rows = userRepository.updateLastLogin(userId, loginCount + 1, remoteAddr, now);
        if (rows != 1) {
            String message = "登录失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE, message);
        }

        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_USER_ID, userId);
        claims.put(CLAIM_USER_NAME, username);
        claims.put(CLAIM_USER_AGENT, userAgent);
        claims.put(CLAIM_REMOTE_ADDR, remoteAddr);
        String jwt = JwtUtils.generate(claims, secretKey);
        log.debug("生成用户的JWT数据：{}", jwt);

        UserCachePO userCachePO = new UserCachePO();
        userCachePO.setEnable(ENABLE_STATE_ON);
        userCachePO.setAuthoritiesJsonString(authoritiesJsonString);
        userCacheRepository.saveUserState(userId, userCachePO);
        log.debug("向缓存中存入用户状态数据：{}", userCachePO);

        UserLoginResultVO userLoginResultVO = new UserLoginResultVO()
                .setId(userId)
                .setUsername(username)
                .setAvatar(avatar)
                .setToken(jwt)
                .setAuthorities(permissions);
        log.debug("即将返回用户的登录结果：{}", userLoginResultVO);
        return userLoginResultVO;
    }

    @Override
    public void logout(CurrentPrincipal currentPrincipal) {
        log.debug("开始处理【退出登录】的业务，参数：{}", currentPrincipal);
        Long userId = currentPrincipal.getId();
        boolean deleteResult = userCacheRepository.deleteUserState(userId);
        if (!deleteResult) {
            String message = "操作失败，用户数据有误！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
    }

}
